﻿using System;
using System.Collections.Generic;
using System.Linq;
using Cjc.Calculation.ExpressionEngine;
using Cjc.Calculation.ExpressionEngine.Excel.Compiler;
using Cjc.Calculation.ExpressionEngine.Excel.Runtime.Binding;
using System.Linq.Expressions;
using Microsoft.Scripting;
using Microsoft.Scripting.Ast;
using System.Reflection;

namespace Cjc.Calculation.ExpressionEngine.Excel.Compiler
{
	public class VariableRewriter : ExpressionVisitor
	{
        private static Expression worksheetExpression = Expression.Property(Expression.Property(DlrParameterResolver.ScopeAndLanguageParameter, "Scope"), "Worksheet");

		internal static readonly MethodInfo GetCellMethod = typeof( ICellContext ).GetMethod( "GetCell", BindingFlags.Public | BindingFlags.Instance );

//		internal static readonly MethodInfo ExecuteMethod = typeof( Cell ).GetProperty( "Value".GetMethod( "Execute", BindingFlags.Public | BindingFlags.Instance );

		private Engine engine;
		private IDictionary<SymbolId, Expression> variables;

		public bool IsOptimized { get; private set; }
		public List<Formula> Dependencies { get; private set; }

		public VariableRewriter( Engine engine, IDictionary<SymbolId, Expression> variables )
		{
			this.engine = engine;
			this.variables = variables;
			Dependencies = new List<Formula>();
		}

		protected override Expression VisitParameter( ParameterExpression node )
		{
            // Leave the parameters added to function calls alone
            if (node.Name == DlrParameterResolver.ScopeAndLanguageParameter.Name)
                return node;

            var symbol = SymbolTable.StringToCaseInsensitiveId(node.Name);

			if ( variables.ContainsKey( symbol ) ) return variables[ symbol ];

			var formula = engine[ symbol ];
			Dependencies.Add( formula );
			IsOptimized = true;

			return Expression.Property(
				Expression.Call(
					worksheetExpression,
					GetCellMethod,
					Expression.Constant( formula ) ),
				"Value" );
/*
			return Expression.Call(
				Expression.Constant( formula ),
				ExecuteMethod,
				scopeExpression );*/
		}
	}
}